package com.hotel.BL;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.EntityName;
import com.Util;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.CompositeFilterOperator;
import com.google.appengine.api.datastore.Query.Filter;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.FilterPredicate;
import com.google.appengine.api.datastore.Query.SortDirection;

import data.Charge;
import data.Folio;
import data.Payment;
import data.SubPayment;

public class PaymentLogic extends AbstractBL {
	
	public PaymentLogic(HttpServletRequest req,HttpServletResponse resp){
		this.req = req;
		this.resp = resp;
	}
	
	public Payment GetPayment(long id) {
		Key key = KeyFactory.createKey(EntityName.Payment, id);
		try {
			Entity lang = datastore.get(key);
			Payment c = new Payment();
			c.setEntity(lang);
			return c;
		} catch (EntityNotFoundException e) {
			return null;
		}
	}

	public Payment GetPayment(long hotelId, String title) {
		Query q = new Query(EntityName.Payment);

		Filter filterHotel = new FilterPredicate("hotelId",
				FilterOperator.EQUAL, hotelId);
		Filter filterStatus = new FilterPredicate("status",
				FilterOperator.EQUAL, true);
		Filter filterAvaliable = new FilterPredicate("avaliable",
				FilterOperator.EQUAL, true);
		Filter filterTitle = new FilterPredicate("title", FilterOperator.EQUAL,
				title);

		Filter filter = CompositeFilterOperator.and(filterHotel, filterStatus,
				filterAvaliable, filterTitle);

		q.setFilter(filter);

		return GetPayment(datastore.prepare(q).asSingleEntity());
	}

	public List<Payment> GetAllPayment(long hotelId) {
		Query q = new Query(EntityName.Payment);

		Filter filterHotel = new FilterPredicate("HotelId",FilterOperator.EQUAL, hotelId);
		Filter filterAvaliable = new FilterPredicate("Avaliable",FilterOperator.EQUAL, true);
		Filter filter = CompositeFilterOperator.and(filterHotel,filterAvaliable);
		q.setFilter(filter).addSort("payDate", SortDirection.DESCENDING);
		return GetList(datastore.prepare(q).asList(
				FetchOptions.Builder.withDefaults()));
	}
	
	
	
	public List<SubPayment> GetAllParentPayment(long hotelId,long parentPaymentId) {	
		Query q = new Query(EntityName.SubPayment);

	Filter filterHotel = new FilterPredicate("HotelId",
			FilterOperator.EQUAL,hotelId);
	Filter filterpPayment = new FilterPredicate("ParentPayment",
			FilterOperator.EQUAL,  String.valueOf(parentPaymentId));
	Filter filter = CompositeFilterOperator.and(filterHotel, filterpPayment);

	q.setFilter(filter);

	return GetSubList(datastore.prepare(q).asList(
			FetchOptions.Builder.withDefaults()));}
	
	public List<Payment> GetPaymentFromDate(long hotelId,Date d) {
		Query q = new Query(EntityName.Payment);

		Filter filterHotel = new FilterPredicate("HotelId",FilterOperator.EQUAL, hotelId);
		Filter filterAvaliable = new FilterPredicate("Avaliable",FilterOperator.EQUAL, true);
		Filter filterPayDate = new FilterPredicate("payDate",FilterOperator.GREATER_THAN_OR_EQUAL, d);
		Filter filterPayDate2 = new FilterPredicate("payDate",FilterOperator.LESS_THAN, Util.addDays(d, 1));
		
		Filter filter = CompositeFilterOperator.and(filterHotel,filterAvaliable,filterPayDate,filterPayDate2);
		q.setFilter(filter).addSort("payDate", SortDirection.DESCENDING);
		//return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withLimit(10)));
		return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withDefaults()));
	}

	public List<Payment> GetPayment10(long hotelId) {
		Query q = new Query(EntityName.Payment);

		Filter filterHotel = new FilterPredicate("HotelId",FilterOperator.EQUAL, hotelId);
		Filter filterAvaliable = new FilterPredicate("Avaliable",FilterOperator.EQUAL, true);
		Filter filter = CompositeFilterOperator.and(filterHotel,filterAvaliable);
		q.setFilter(filter).addSort("payDate", SortDirection.DESCENDING);
		return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withLimit(10)));
	}
	public Payment GetPayment(Entity entity) {
		Payment item = new Payment();
		item.setEntity(entity);
		return item;
	}

	public List<Payment> GetList(List<Entity> entities) {
		List<Payment> list = new ArrayList<Payment>();
		if(entities!=null)
		for (Entity e : entities) {
			Payment a = new Payment();
			a.setEntity(e);
			list.add(a);
		}
		return list;
	}
	
	public List<SubPayment> GetSubList(List<Entity> entities) {
		List<SubPayment> list = new ArrayList<SubPayment>();
		if(entities!=null)
		for (Entity e : entities) {
			SubPayment a = new SubPayment();
			a.setEntity(e);
			list.add(a);
		}
		return list;
	}

	public Payment AddPayment(long hotelId, double amount,long creditCardId, String ccNo, String ccNo2,
			Date payDate, String payMode, String paytype, String description,
			String parentPaymentString, boolean isSplit, String resId,long counterId)
			throws EntityNotFoundException {
		Payment t = new Payment();
		t.setHotelId(hotelId);
		t.setAmount(amount);
		t.setCreditCardId(creditCardId);
		t.setCcNo(ccNo);
		t.setCcNo2(ccNo2);
		t.setPayDate(payDate);
		t.setPayMode(payMode);
		t.setPayTypeString(paytype);
		t.setDescription(description);
		t.setParentPaymentString(parentPaymentString);
		t.setAvaliable(true);
		t.setResIdString(resId);
		t.setCounterId(counterId);
		Key k = datastore.put(t.getEntity());
		t.setId(k.getId());
		t.setKey(k);

		return t;
	}
	public boolean RemovePayment(long paymentId) {
		Key key = KeyFactory.createKey(EntityName.Payment, paymentId);
		datastore.delete(key);
		return true;
	}
	public double CalculatePayment(String paymentId, long hotelId)throws EntityNotFoundException {
		double result=0;
		double sumAmountA =0;
		String [] ArraypaymentId =paymentId.split(",");
		//List<Payment> list = new ArrayList<Payment>();
		for(int i=0;i<ArraypaymentId.length;i++)
		{
			if(!ArraypaymentId[i].equals("")){
		Payment pm = new PaymentLogic(req,resp).GetPayment(Long.parseLong(ArraypaymentId[i].trim()));
		List<SubPayment> p = new PaymentLogic(req,resp).GetAllParentPayment(hotelId,Long.parseLong(ArraypaymentId[i].trim()));
			for(SubPayment payM: p)
			{
				if(payM.getFolioId() ==0)
				{
					sumAmountA+=payM.getAmount();
				}
				
				
			}
			
			
			if(p.isEmpty()==true)
			{
				result +=pm.getAmount();
			}
			else
			{
				result +=sumAmountA;
			}
												}
		
		}
		return result;
	
	}

	public Payment EditResIdPayment(long hotelId, long int_id, String resId)
			throws EntityNotFoundException, ParseException {
		Payment g = GetPayment(int_id);
		g.setResIdString(resId);
		Key k = datastore.put(g.getEntity());
		g.setId(k.getId());
		g.setKey(k);
		return g;
	}
	
	public double SetFolio(String listFolio,String listPayment,Long hotelId) throws NumberFormatException, EntityNotFoundException
	{
		double chargeSum = 0;
		double paymentSum = 0;
		double checkchargeSum = 0;
		double checkpaymentSum = 0;
		double payAmount =0;
		String newPaymentList ="";
		String []  folioList = listFolio.trim().split(",");
		//String []  pLaymentist= listPayment.trim().split(",");
		//SubPayment ss = new SubPayment();
		String []  pLaymentist = null;
		FolioLogic folioLogic = new FolioLogic(req,resp);
		PaymentLogic paymentLogic = new PaymentLogic(req,resp);
		ChargeLogic chargeLogic = new ChargeLogic(req,resp);
		for(int i=0;i<folioList.length;i++)
		{
			Folio f = folioLogic.GetFolio(Long.parseLong(folioList[i]));
			
			String [] cStringList = f.getChargeString().trim().split(",");
				
				for(int c =0 ;c<cStringList.length;c++)
				{
					if(cStringList[c]!= null && !cStringList[c].equals("")){
					Charge ch = chargeLogic.GetCharge(Long.parseLong(cStringList[c]));
					
					//double tax =new TaxLogic().CalTax(hotelId, ch.getChargeAmount());
						if(ch.isRefund() == true)
						{
							checkchargeSum -= ch.getChargeAmount()+ch.getTax();
						}else
						{
							checkchargeSum += ch.getChargeAmount()+ch.getTax();
						}
					}
					pLaymentist= listPayment.trim().split(",");
				}
		}
		for(int u=0;u<pLaymentist.length;u++)
		{
			Payment ps = paymentLogic.GetPayment(Long.parseLong(pLaymentist[u]));
			checkpaymentSum+=ps.getAmount();	
			
			double pscal = paymentLogic.CalculatePayment(pLaymentist[u], hotelId);
			if(pscal != 0)
			{
				if(newPaymentList.equals(""))
				{
					newPaymentList +=pLaymentist[u];
				}
				else
				{
					newPaymentList +=","+pLaymentist[u];
				}
			}
		}
		System.out.println("checkpaymentSum="+checkpaymentSum);
		System.out.println("checkchargeSum="+checkchargeSum);
		
		if(checkpaymentSum == checkchargeSum  )
		{
			SubPaymentLogic subPaymentLogic = new SubPaymentLogic(req,resp);
		for(int i=0;i<folioList.length;i++)
		{
			 chargeSum = 0;
			 paymentSum = 0;
				Folio f = folioLogic.GetFolio(Long.parseLong(folioList[i]));
				String [] cStringList = f.getChargeString().trim().split(",");
				
				for(int c =0 ;c<cStringList.length;c++)
				{
				if(cStringList[c]!= null && !cStringList[c].equals("")){
					Charge ch = chargeLogic.GetCharge(Long.parseLong(cStringList[c]));
					
					//double tax =new TaxLogic().CalTax(hotelId, ch.getChargeAmount());
					if(ch.isRefund() == true)
					{
						
						chargeSum -= ch.getChargeAmount()+ch.getTax();
					}else
					{
						chargeSum += ch.getChargeAmount()+ch.getTax();
					}
																		}
				}
				System.out.print("chargeSum="+chargeSum);
				if(f.getPaymentString() != null)
				{
					String [] fPayment = f.getPaymentString().trim().split(",");
					for(int u=0;u<fPayment.length;u++)
					{
						SubPayment ps = subPaymentLogic.GetSubPayment(Long.parseLong(fPayment[u]));
							paymentSum+=ps.getAmount();		
					}
				
				}else
				{
					paymentSum=0;
					
				}
			
			if(chargeSum == paymentSum)
			{
				continue;
			}
			else
			{
				payAmount=paymentLogic.CalculatePayment(newPaymentList, hotelId);
				
				if(chargeSum < paymentSum)
				{
					if(payAmount != 0 && payAmount<0)
					{
						subPaymentLogic.RoutePayment(newPaymentList,chargeSum,Long.parseLong(folioList[i]), hotelId);
						
					}
				}
				else if(chargeSum > paymentSum)
				{
					if(payAmount != 0 )
					{
						subPaymentLogic.RoutePayment(newPaymentList,chargeSum,Long.parseLong(folioList[i]), hotelId);
						
					}

				}
				
				
			}
				
			 chargeSum = 0;
			 paymentSum = 0;
		
		}
		
			return 1;
		}
		else
		{
			return 0;
		}
		
	}

	public double GetPayMentInCounterByPayMode(long hotelId,long counterid
			,Date dateFrom,Date dateTo,long mode){
		List<Payment> list = GetPayMentList(hotelId,counterid,dateFrom,dateTo,mode);
		double sum = 0;
		for(int i=0;i<list.size();i++){
			sum += list.get(i).getAmount();
		}
		return sum;
	}
	
	public List<Payment> GetPayMentList(long hotelId,long counterid
			,Date dateFrom,Date dateTo,long payMode) {
		Query q = new Query(EntityName.Payment);

		Filter filterHotel = new FilterPredicate("HotelId",
				FilterOperator.EQUAL, hotelId);
		Filter filterAvaliable = new FilterPredicate("Avaliable",
				FilterOperator.EQUAL, true);
		Filter filterCounterId = new FilterPredicate("counterId",
				FilterOperator.EQUAL, counterid);
		Filter filterDateFrom = new FilterPredicate("payDate",
				FilterOperator.GREATER_THAN_OR_EQUAL, dateFrom);
		Filter filterDateTo = new FilterPredicate("payDate",
				FilterOperator.LESS_THAN_OR_EQUAL, dateTo);
		Filter filterPayMode = new FilterPredicate("payMode",
				FilterOperator.EQUAL, String.valueOf(payMode));
		Filter filter = CompositeFilterOperator.and(filterHotel,
				filterAvaliable,filterCounterId,
				filterDateFrom,filterDateTo,filterPayMode);
		q.setFilter(filter);
		return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withDefaults()));
	}
}
